/*
Kakine
ActionScript Framework
Copyright © 2011, PUNY, LLC.

This file is part of KAKINE.

KAKINE is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

KAKINE is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with KAKINE.  If not, see <http://www.gnu.org/licenses/>.
*/ 
package com.puny.mvc.helpers
{	
	import flash.display.DisplayObject;
	import flash.events.Event;
	
	internal class EnterFrameContext extends Context {
//		private static var _pool:Array = new Array();
		private var _owner:DisplayObject;
		private var _mainLoop:Function;
		private static const _listeners:Array = new Array();
		private static const _keys:Array = new Array();
		private static var _root:DisplayObject;
		
		private static function addListeners(owner:DisplayObject, listener:Function, key:Function):void {
			if (_root == null && owner != null && owner.root != null) {
				_root = owner.root;
			}

//			var length:int = _listeners.length;
//			for(var i:int = 0;i < length;i++) {
//				if (_listeners[i] != null && _listeners[i][0] == key) {
//					_listeners.splice(i,1);	
//				}
//			}
			
			_listeners.push([key, listener]);
			if (_listeners.length == 1) {
				_root.addEventListener(Event.ENTER_FRAME, staticLoopHandler); 
			}
		}
		
		private static function staticLoopHandler(event:Event):void {
			_listeners.forEach(invokeListener);
		}
		
		private static function invokeListener(listener:Array, index:int, arr:Array):void {
			if (listener != null) {
				listener[1](null);
			}
		}
		
		private static function removeListeners(listener:Function):void {
			var length:int = _listeners.length;
			for(var i:int = 0;i < length;i++) {
				if (_listeners[i][1] == listener) {
					_listeners.splice(i,1);
					if (_root != null && _listeners.length == 0) {
						_root.removeEventListener(Event.ENTER_FRAME, staticLoopHandler);
					}
					return;
				}
			}
		}
		
		
		public function EnterFrameContext() {
		}

		public static function getInstance(owner:DisplayObject, 
									before:Function=null, 
									mainLoop:Function=null, 
									after:Function=null):Context {
			var context:EnterFrameContext;
//			if (_pool.length == 0) {
				context = new EnterFrameContext();
//			} else {
//				context = _pool.shift();
//			}
			context.initialize(owner,before,mainLoop,after);
			return context;
		}
		
		private function initialize(owner:DisplayObject, 
									before:Function, 
									mainLoop:Function, 
									after:Function):void {
			_owner = owner;
			_mainLoop = mainLoop;
			setup(before,after);
			if (owner == null) {
				throw new ArgumentError("The first argument must not be null.");
			}
		}
		
		public static function debug():void {
			for each(var handler:Context in handlers) {
				if (handler is EnterFrameContext) {
					trace((handler as EnterFrameContext)._owner,(handler as EnterFrameContext)._owner.name);
					trace((handler as EnterFrameContext)._mainLoop());
				}
			}
		}	
		
		public static function clear():void {
			var handler:Context;
			_root.removeEventListener(Event.ENTER_FRAME, staticLoopHandler);
			while(handlers.length > 0) {
				handler = handlers.pop();
				if (handler is EnterFrameContext) {
					(handler as EnterFrameContext)._owner = null;
					(handler as EnterFrameContext)._mainLoop = null;
				}
			}
			_root = null;
		}
		
		override public function start():void {
			addListeners(_owner, loopHandler, _mainLoop);			
//			if (_owner != null) {
//				_owner.addEventListener(Event.ENTER_FRAME, loopHandler);
//			}
		}

		override public function resume():void {
			start();
		}
		
		override public function stop():void {
			removeListeners(loopHandler);
//			if (_owner != null) {
//				_owner.removeEventListener(Event.ENTER_FRAME, loopHandler);
//			}
		}
		
		override protected function cleanUp():void {
//			trace("owner:"+_owner+"("+_owner.name+") was cleaned up");
			_owner = null;
			_mainLoop = null;
			super.cleanUp();
//			_pool.push(this);
		}
				
		private function loopHandler(event:Event):void {
			if (_mainLoop != null) {
				if (_mainLoop()) {
					return;
				}
			}
			wrapUp();
			dispatch(DONE);
		}
		
	}
}